package cn.changeforyou.web.dao.mybatis.ext.metaInfo.parser;

import cn.changeforyou.utils.string.StringUtils;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.annotations.IdTypeAnnotation;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.EntityMetaInfo;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.FieldMetaInfo;
import cn.changeforyou.web.dao.mybatis.ext.metaInfo.IdTypeEnum;
import cn.changeforyou.web.utils.NameUtils;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.springframework.core.annotation.AnnotationUtils;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * 实体类元数据解析器解析器
 *
 * @author zhyu
 * @version 1.0
 * @date 2022/2/10 16:06
 * @see EntityMetaInfo
 */
public class EntityMetaInfoParser {

    /**
     * 解析实体类元数据
     *
     * @param entityClass
     * @return
     */
    public static EntityMetaInfo parseEntity(Class entityClass) {
        EntityMetaInfo entityMetaInfo = new EntityMetaInfo();
        entityMetaInfo.setEntityClass(entityClass);

        Table jpaAnnotation = AnnotationUtils.findAnnotation(entityClass, Table.class);
        TableName mybatisPlusAnnotation = AnnotationUtils.findAnnotation(entityClass, TableName.class);
        String tableName = null;
        if (null != jpaAnnotation) {
            tableName = jpaAnnotation.name();
        } else if (null != mybatisPlusAnnotation) {
            tableName = mybatisPlusAnnotation.value();
        } else {
            tableName = NameUtils.getUnderLineName(entityClass.getName());
        }
        entityMetaInfo.setTableName(tableName);

        List<FieldMetaInfo> fieldMetaInfos = new ArrayList<>();
        entityMetaInfo.setFieldMetaInfoList(fieldMetaInfos);
        for (Field field : ReflectUtil.getFields(entityClass)) {
            //过滤掉静态变量
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }

            //带jpa注解Transient的也过滤
            if (field.isAnnotationPresent(Transient.class)) {
                continue;
            }

            FieldMetaInfo fieldMetaInfo = new FieldMetaInfo();
            fieldMetaInfo.setFieldClass(field.getDeclaringClass());
            fieldMetaInfo.setFieldName(field.getName());

            TableField tableField = field.getAnnotation(TableField.class);
            Column column = field.getAnnotation(Column.class);
            if (null != tableField) {
                if (tableField.exist()) {
                    fieldMetaInfo.setColumnName(tableField.value());
                    fieldMetaInfo.setTypeHandlerClass(tableField.typeHandler());
                    fieldMetaInfo.setJdbcType(tableField.jdbcType());
                } else {
                    continue;
                }
            } else if (null != column) {
                fieldMetaInfo.setColumnName(column.name());
            } else {
                fieldMetaInfo.setColumnName(NameUtils.getUnderLineName(field.getName()));
            }

            TableId tableId = field.getAnnotation(TableId.class);
            Id id = field.getAnnotation(Id.class);
            IdTypeEnum idTypeEnum = null;
            if (tableId != null) {
                fieldMetaInfo.setId(true);
                String value = tableId.value();
                if (StringUtils.isNotBlank(value)) {
                    fieldMetaInfo.setColumnName(value);
                }
                IdType type = tableId.type();
                if (type == IdType.NONE) {
                    idTypeEnum = IdTypeEnum.none;
                }else if(type == IdType.AUTO) {
                    idTypeEnum = IdTypeEnum.auto;
                }
            } else if (null != id) {
                fieldMetaInfo.setId(true);
            }
            IdTypeAnnotation annotation = field.getAnnotation(IdTypeAnnotation.class);
            if(null != annotation) {
                idTypeEnum = annotation.value();
            }

            if(null != idTypeEnum) {
                fieldMetaInfo.setIdTypeEnum(idTypeEnum);
            }

            fieldMetaInfos.add(fieldMetaInfo);
        }
        return entityMetaInfo;
    }

    /**
     * 解析实体类元数据
     *
     * @param voClass
     * @return
     */
    public static EntityMetaInfo parseVO(Class voClass) {
        EntityMetaInfo entityMetaInfo = new EntityMetaInfo();
        entityMetaInfo.setEntityClass(voClass);

        List<FieldMetaInfo> fieldMetaInfos = new ArrayList<>();
        entityMetaInfo.setFieldMetaInfoList(fieldMetaInfos);
        for (Field field : ReflectUtil.getFields(voClass)) {
            //过滤掉静态变量
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }

            //带jpa注解Transient的也过滤
            if (field.isAnnotationPresent(Transient.class)) {
                continue;
            }

            FieldMetaInfo fieldMetaInfo = new FieldMetaInfo();
            fieldMetaInfo.setFieldClass(field.getDeclaringClass());
            fieldMetaInfo.setFieldName(field.getName());

            TableField tableField = field.getAnnotation(TableField.class);
            Column column = field.getAnnotation(Column.class);
            if (null != tableField) {
                if (tableField.exist()) {
                    fieldMetaInfo.setColumnName(tableField.value());
                    fieldMetaInfo.setTypeHandlerClass(tableField.typeHandler());
                    fieldMetaInfo.setJdbcType(tableField.jdbcType());
                } else {
                    continue;
                }
            } else if (null != column) {
                fieldMetaInfo.setColumnName(column.name());
            } else {
                fieldMetaInfo.setColumnName(NameUtils.getUnderLineName(field.getName()));
            }

            fieldMetaInfos.add(fieldMetaInfo);
        }
        return entityMetaInfo;
    }
}
